package org.example.rzfx.service;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.rzfx.dto.LoginDTO;
import org.example.rzfx.entity.User;
import org.example.rzfx.mapper.UserMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 用户服务
 */
@Service
public class UserService extends ServiceImpl<UserMapper, User> {
    
    @Resource
    private RedisService redisService;
    
    /**
     * 用户登录
     */
    public Map<String, Object> login(LoginDTO loginDTO) {
        // 查询用户
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, loginDTO.getUsername());
        User user = this.getOne(wrapper);
        
        if (user == null) {
            throw new RuntimeException("用户名或密码错误");
        }
        
        if (user.getStatus() == 0) {
            throw new RuntimeException("用户已被禁用");
        }
        
        // 验证密码
        if (!BCrypt.checkpw(loginDTO.getPassword(), user.getPassword())) {
            throw new RuntimeException("用户名或密码错误");
        }
        
        // 登录成功，生成token
        StpUtil.login(user.getId());
        String token = StpUtil.getTokenValue();
        
        // 将用户信息缓存到Redis（7天过期）
        String userCacheKey = RedisService.userCacheKey(user.getId());
        user.setPassword(null); // 不缓存密码
        redisService.set(userCacheKey, user, 7, TimeUnit.DAYS);
        
        // 记录在线用户
        String onlineKey = RedisService.onlineUserKey(user.getId());
        Map<String, Object> onlineInfo = new HashMap<>();
        onlineInfo.put("userId", user.getId());
        onlineInfo.put("username", user.getUsername());
        onlineInfo.put("role", user.getRole());
        onlineInfo.put("loginTime", LocalDateTime.now());
        redisService.set(onlineKey, onlineInfo, 7, TimeUnit.DAYS);
        
        // 在Sa-Token Session中存储角色信息
        StpUtil.getSession().set("role", user.getRole());
        StpUtil.getSession().set("username", user.getUsername());
        
        // 返回用户信息和token
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("userId", user.getId());
        result.put("username", user.getUsername());
        result.put("role", user.getRole());
        result.put("email", user.getEmail());
        result.put("phone", user.getPhone());
        
        return result;
    }
    
    /**
     * 退出登录
     */
    public void logout() {
        Long userId = StpUtil.getLoginIdAsLong();
        
        // 删除Redis缓存
        redisService.delete(RedisService.userCacheKey(userId));
        redisService.delete(RedisService.onlineUserKey(userId));
        
        // Sa-Token退出
        StpUtil.logout();
    }
    
    /**
     * 获取当前登录用户
     */
    public User getCurrentUser() {
        Long userId = StpUtil.getLoginIdAsLong();
        
        // 先从Redis获取
        String cacheKey = RedisService.userCacheKey(userId);
        User user = redisService.get(cacheKey, User.class);
        
        if (user != null) {
            return user;
        }
        
        // Redis没有，从数据库查询并缓存
        user = this.getById(userId);
        if (user != null) {
            user.setPassword(null); // 不缓存密码
            redisService.set(cacheKey, user, 7, TimeUnit.DAYS);
        }
        
        return user;
    }
    
    /**
     * 创建用户
     */
    public void createUser(User user) {
        // 检查用户名是否已存在
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, user.getUsername());
        if (this.count(wrapper) > 0) {
            throw new RuntimeException("用户名已存在");
        }
        
        // 加密密码
        user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt()));
        this.save(user);
    }
    
    /**
     * 修改密码
     */
    public void changePassword(String oldPassword, String newPassword) {
        // 获取当前登录用户ID
        Long userId = StpUtil.getLoginIdAsLong();
        
        // ⚠️ 必须从数据库查询用户，因为缓存中的密码字段是null
        User user = this.getById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        
        // 验证原密码
        if (!BCrypt.checkpw(oldPassword, user.getPassword())) {
            throw new RuntimeException("原密码错误");
        }
        
        // 更新为新密码
        user.setPassword(BCrypt.hashpw(newPassword, BCrypt.gensalt()));
        this.updateById(user);
        
        // 清除用户缓存
        String userCacheKey = RedisService.userCacheKey(user.getId());
        redisService.delete(userCacheKey);
    }
    
    /**
     * 重置密码
     */
    public void resetPassword(Long userId, String newPassword) {
        User user = this.getById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        
        user.setPassword(BCrypt.hashpw(newPassword, BCrypt.gensalt()));
        this.updateById(user);
    }
}

